package com.rtsapp.server.monitor;

import com.rtsapp.server.logger.Logger;

/**
 * 超时的监控任务
 */
public final class TimeoutMonitorTask implements IMonitorTask {

    private static final Logger LOGGER =com.rtsapp.server.logger.LoggerFactory.getLogger( MonitorThread.class );


    private static final long DEFAULT_PROCESSING_TIMEOUT = 10 * 1000;//10秒为超时

    /**
     * 业务线程
     */
    private final Thread thread;

    /**
     * 是否正在处理业务
     */
    private boolean processingTask = false ;

    /**
     * 业务处理开始时间
     * 毫秒
     */
    private long startTime;

    /**
     * 业务处理结束时间
     * 单位毫秒
     */
    private long endTime;


    private TimeoutMonitorTask(Thread t){
        this.thread = t;
    }


    /**
     * 开始一次业务处理
     * 注意: 只能业务线程调用
     */
    private void innerStartProcess(){
        startTime = System.currentTimeMillis();
        processingTask = true;
    }

    /**
     * 结束一次业务处理
     * 注意: 只能业务线程调用
     */
    private void innerEndProcess(){
        endTime = System.currentTimeMillis();
        processingTask = false;
    }


    @Override
    public void monitor( ) {

        //如果线程状态是死亡啦，进行重启

        //如果线程是运行状态，或者线程是阻塞状态，且逻辑已经超时

        if( processingTask ){
            if( isTimeout() ){
                LOGGER.error(thread.getName() + " : 检测到该线程执行时间过长, 将采取中断操作, 线程堆栈信息如下:");

                dumpThread();

                interruptThread();
            }
        }


    }

    private boolean isTimeout(){
        return (System.currentTimeMillis() - startTime) > DEFAULT_PROCESSING_TIMEOUT;
    }


    private void dumpThread(){

        StringBuilder sb = new StringBuilder();
        sb.append( "\r\n" );
        StackTraceElement[] trace = thread.getStackTrace();
        for (StackTraceElement traceElement : trace) {
            sb.append( "\tat " + traceElement);
            sb.append( "\r\n" );
        }

        LOGGER.error( sb.toString() );

    }

    private void interruptThread(){
        try {
            thread.interrupt();

            LOGGER.error( thread.getName() + " : 被中断执行");

        }catch( Throwable ex) {
            LOGGER.error(thread.getName() + " : 中断执行失败", ex );
        }

    }



    private static ThreadLocal<TimeoutMonitorTask> moniterLocal = new ThreadLocal<>();

    public static void startProcess(){

        TimeoutMonitorTask monitor = moniterLocal.get();
        if( monitor == null ){
            System.out.println( Thread.currentThread().getName()+ ": 创建TimeoutMonitorTask");
            monitor = new TimeoutMonitorTask( Thread.currentThread() );
            moniterLocal.set( monitor );
            MonitorThread.getInstance().addMonitor( monitor );
        }

        monitor.innerStartProcess();
    }

    public static void endProcess(){
        TimeoutMonitorTask monitor = moniterLocal.get();
        if( monitor != null ){
            monitor.innerEndProcess();
        }else{
            //error
        }
    }

}
